/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package UserManager;

import MessageHandler.message_type;
import MessageHandler.messagehandler;
import MessageHandler.messages;
import MessageHandler.submessage;
import configuration.config_manager;
import java.io.IOException;
import java.net.*;
import postmaster.postmaster;

/**
 *
 * @author maniksin
 */
public class usermanager {
    
    String[] args;
    config_manager conf;
    messagehandler msg;
    
    private boolean wait_for_reply;
    
    private final int O = 0;   // Optional switch without argument
    private final int OA = 1;  // Optional switch with argument
    private final int M = 2;  // Mandatory switch (with argument)
    
    private void print_usage() {
        System.err.println("[...] <peer_name> <command>");
    }
    
    private int parse_switches(String[] switches, int[] switch_types, String[] switch_args) {
                
        int i;
        int j;

        for (i = 1; i < args.length; i++) {
            

            for (j = 0; j < switches.length; j++) {
                
                if (args[i].equals(switches[j])) {
                    
                    if (switch_types[j] == M || switch_types[j] == OA) {
                        // Next argument is the switch value
                        if (i == args.length - 1) {
                            // This was the last argument
                            System.err.println("Empty switch " + args[i]);
                            return 0;
                        } else {
                            switch_args[j] = args[i+1];
                            i++;
                            break;
                        }
                    } else {
                        switch_args[j] = "1";
                        break;
                    }
                }
            }
            
            if (j == switches.length) {
                // No switch matched
                // It must be a param
                break;
            }
        }
        
        // Check if any mandatory switch is not provided
        for (j = 0; j < switches.length; j++) {
            if (switch_types[j] == M && switch_args[j] == null) {
                System.err.println(args[0] + ": Mandatory switch " + switches[j] + " not provided");
                return 0;
            }
        }
        
        return i;
    }
    
    private boolean build_default_message(submessage msg_id, String peer, String type, int params_position) {
        
        msg = new messagehandler();
        
        msg.msg_id = messages.USER_COMMAND;
        msg.source = "user";
        msg.dest = peer;
        msg.sub_msg_id = msg_id;
        
        if ("none".equals(type)) {
            msg.type = message_type.ACKNOWLEDGE_NONE;
        } else if ("receipt".equals(type)) {
            msg.type = message_type.ACKNOWLEDGE_RECEIPT;
        } else if ("action".equals(type) || type == null) {
            msg.type = message_type.ACKNOWLEDGE_ACTION;
        } else {
            System.err.println("Invalid option for -ack");
            return false;
        }
                
        msg.user_ip = "0.0.0.0";
        msg.user_port = 0;
        
        msg.cmd_string = new String[args.length - params_position];
        for (int i = 0; i < msg.cmd_string.length; i++) {
            msg.cmd_string[i] = args[params_position + i];
        }
        
        return true;
    }
    private boolean parse_exec_command() {
        
        String[] switches = {"-peer", "-ack",};
        int[] switch_types = {M, OA};
        String[] switch_args = new String[switches.length];
        
        int param_position = parse_switches(switches, switch_types, switch_args);
        if (param_position == 0) { return false; }
        
        // For external command, at least one param should be provided
        if (param_position == args.length) {
            System.err.println("No commmand provided to execute!!");
            return false;
        }
        
        return build_default_message(submessage.EXTERNAL_COMMAND, switch_args[0], switch_args[1], param_position);
}
    private void handle_list_reply(messagehandler msg) {
        
        for (int i = 0; i < msg.cmd_string.length; i++) {
            System.out.println(msg.cmd_string[i]);
        }
        
    }
    private boolean parse_list_command() {
        
        String[] switches = {"-peer"};
        int[] switch_types = {OA};
        String[] switch_args = new String[switches.length];
        
        int param_position = parse_switches(switches, switch_types, switch_args);
        if (param_position == 0) { return false; }
        
        // For list command, there are no arguments except switches
        if (param_position != args.length) {
            System.err.println("No arguments expected for list command");
            return false;
        }
        
        if (switch_args[0] == null) {
            // Peer not provided. Mark it as post-master itself
            switch_args[0] = conf.my_name;
        }
        
        if (build_default_message(submessage.LIST_COMMANDS, switch_args[0], "action", param_position) == false) {
            return false;
        }
        
        return true;
    }
    
    private boolean parse_announce_command() {
        
        String[] switches = {"-peer", "-ack", "-title",};
        int[] switch_types = {M, OA, OA};
        String[] switch_args = new String[switches.length];
        
        int param_position = parse_switches(switches, switch_types, switch_args);
        if (param_position == 0) { return false; }
        
        // For announcement command, exactly one param should be provided
        if (param_position <  args.length - 1) {
            System.err.println("Multiple strings provided to announce!!");
            return false;
        } else if (param_position == args.length) {
            System.err.println("Text to announce not provided");
            return false;
        }
        
        if (build_default_message(submessage.ANNOUNCEMENT, switch_args[0], switch_args[1], param_position) == false) {
            return false;
        }
        
        msg.cmd_string = new String[2];
        msg.cmd_string[0] = switch_args[2];     // title
        msg.cmd_string[1] = args[param_position]; // message
        
        wait_for_reply = false;
        return true;
}
    
    
    private boolean parse_command() {
                
        if (args[0].equals(submessage.EXTERNAL_COMMAND.cmd)) {
            return parse_exec_command();
        } else if (args[0].equals(submessage.ANNOUNCEMENT.cmd)) {
            return parse_announce_command();
        } else if (args[0].equals(submessage.LIST_COMMANDS.cmd)) {
            return parse_list_command();
        }
        
        System.err.println("Unknown command " + args[0]);
        System.err.println("Use " + submessage.LIST_COMMANDS.cmd + " to list all commands");
        
        return false;
    }
    
    private void post_command() {
        
        DatagramSocket sock;
        try {
            // Open a socket and send to the server
            sock = new DatagramSocket();
        } catch (SocketException ex) {
            System.err.println("Could not open socket");
            return;
        }
        
        /* int total_length = messagehandler.FIXED_PAYLOAD_LEN + peer.length() + 
                msg.user_ip.length() + command.length(); */
        
        //byte[] buffer = new byte[total_length];
        DatagramPacket dp;
        dp = messagehandler.create_message(msg);
        try {
            dp.setAddress(InetAddress.getByName("127.0.0.1"));
        } catch (UnknownHostException ex) {
            System.err.println("Could not bind socket");
        }
        
        dp.setPort(conf.get_my_port(postmaster.DEFAULT_BIND_PORT));
        try {
            sock.send(dp);
        } catch (IOException ex) {
            System.err.println("Could not send message");
            return;
        }
        
        
        if (!wait_for_reply) {
            return;
        }
        
        // Wait for reply
        dp = new DatagramPacket(
                    new byte[messagehandler.MAX_MSG_PAYLOAD_LEN], messagehandler.MAX_MSG_PAYLOAD_LEN);
        //peer stored_peer;
        messagehandler reply_msg;
        
        try {
            sock.receive(dp);
        } catch (IOException ex) {
             return;
        }
        
        reply_msg = messagehandler.decode_message(dp);
        if (reply_msg.msg_id != messages.USER_REPLY) {
            System.err.println("Unknown reply received");
            return;
        }
        
        // Just print it
        switch(reply_msg.sub_msg_id) {
            case LIST_COMMANDS:
                handle_list_reply(reply_msg);
                break;
            default: 
                System.out.print(reply_msg.cmd_string[0]);
                break;
        }
        
        
    }
    
    public usermanager(String[] args, config_manager conf) {
        this.args = args;
        this.conf = conf;
        wait_for_reply = true;
        
        if (parse_command()) {
            post_command();
        }
        
    }
    
    
    
}
